package common

import (
	"context"
	"encoding/json"
	"fmt"
	"github.com/gorhill/cronexpr"
	"net/http"
	"strings"
	"time"
)

//任务信息
type Job struct {
	Name     string `json:"name"`
	Command  string `json:"command"`
	CronExpr string `json:"cronExpr"`
}

//apiServer 接口应答
type Response struct {
	ErrNo int         `json:"err_no"`
	Msg   string      `json:"msg"`
	Data  interface{} `json:"data"`
}

//定义一个推送给Scheduler的结构
type JobEvent struct {
	//save || delete
	EventType int
	//concrete job
	Job *Job
}

//定义某个job的调度计划信息
type JobSchedulePlan struct {
	Job *Job
	//开源库解析好的cron表达式对象
	Expr *cronexpr.Expression
	//任务 下次调度时间
	NextExecTime time.Time
}

func BuildJobEvent(eventType int, ConcreteJob *Job) (jobEvent *JobEvent) {
	return &JobEvent{
		EventType: eventType,
		Job:       ConcreteJob,
	}
}

type LogRecord struct {
	http.ResponseWriter
	status int
}

//多条日志
type LogBatch struct {
	Logs []interface{}
}

//logSinkError chan的结构
type LogSinkError struct {
	ErrorInfo string
	Err       string
}

//任务执行状态，是正在执行的状态的记录map
type JobExecuteInfo struct {
	//需要知道是哪个任务
	Job *Job
	//理论上的调度时间，scheduleTime。可能多次调度，也可能有误差。可根据这两个时间来判断出是否有调度与执行的延迟误差。
	PlanExecTime time.Time
	//实际的执行时间
	RealExecTime time.Time
	//任务command的context，需要执行的
	CancelCtx context.Context
	//用于取消command执行的cancel函数
	CancelFunc context.CancelFunc
}

func (r *LogRecord) Write(p []byte) (int, error) {
	return r.ResponseWriter.Write(p)
}

//mongo日志的过滤条件
type JobLogFilter struct {
	JobName string `bson:"JobName"`
}

//mongo日志的排序字段
type JobLogSortByStartTime struct {
	SortOrder int `bson:"startTime"`
}

func (r *LogRecord) WriteHeader(status int) {
	r.status = status
	r.ResponseWriter.WriteHeader(status)
}

func BuildResponse(errno int, msg string, data interface{}) (resp []byte, err error) {
	////定义
	//ApiResponse := &Response{
	//	ErrNo: errno,
	//	Msg:   msg,
	//	Data:  data,
	//}
	//
	////序列化返回
	//resp, err = json.Marshal(ApiResponse)
	//return

	// 1, 定义一个response
	var (
		response Response
	)

	response.ErrNo = errno
	response.Msg = msg
	response.Data = data
	//// 2, 序列化json
	resp, err = json.Marshal(response)
	return

}

//反序列化job
func UnpackJob(data []byte) (ret *Job, err error) {
	var (
		//定义一个job指针
		jobReturn *Job
	)
	//初始化这个job指针的内存
	jobReturn = &Job{}
	if err = json.Unmarshal(data, jobReturn); err != nil {
		return
	}
	//没有报错就把这个返回的指针赋值到参数里
	ret = jobReturn
	return
}

//从etcd的event.kv.key中取得后面的jobName
func ExtractJobName(key string) string {
	return strings.TrimPrefix(key, JOB_SAVE_DIR)
}

//构造任务执行计划，返回任务计划执行表
func BuildJobSchedulerPlan(job *Job) (jobPlan *JobSchedulePlan, err error) {
	var (
		express *cronexpr.Expression
	)
	//解析cron表达式
	if express, err = cronexpr.Parse(job.CronExpr); err != nil {
		return
	}
	jobPlan = &JobSchedulePlan{
		Job:  job,
		Expr: express,
		//传递一个当前时间即可得到下次执行时间
		NextExecTime: express.Next(time.Now()),
	}

	fmt.Println("build了一个plan的Schedule,", jobPlan.Job.Name)
	return
}

//构建执行状态信息，是根据计划来衍生出来执行
func BuildJobExecuteInfo(jobPlan *JobSchedulePlan) (jobExecuteInfo *JobExecuteInfo) {
	jobExecuteInfo = &JobExecuteInfo{
		Job:          jobPlan.Job,
		PlanExecTime: jobPlan.NextExecTime, //计划（实际的）调度时间
		RealExecTime: time.Now(),
	}
	jobExecuteInfo.CancelCtx, jobExecuteInfo.CancelFunc = context.WithCancel(context.TODO())
	return
}

//exec 的执行结果
type JobExecuteResult struct {
	//执行信息
	ExecuteInfo *JobExecuteInfo
	Output      []byte
	Err         error
	StartTime   time.Time
	EndTime     time.Time
}

//任务执行日志
type JobLog struct {
	JobName string `json:"job_name"`
	Command string `json:"command"`
	Err     string `json:"err"`
	Output  string `json:"output"`
	//理论上的调度时间，scheduleTime。可能多次调度，也可能有误差。可根据这两个时间来判断出是否有调度与执行的延迟误差。
	PlanExecTime int64 `json:"planExecTime"`
	ScheduleTime int64 `json:"scheduleTime"` //实际调度时间
	//实际的开始执行时间
	RealExecTime int64 `json:"realExecTime"` //实际执行时间
	EndTime      int64 `json:"end_time"`     //任务执行完成时间
}

//提取worker ip 从/cron/worker/192.178.12.1 提取192.178.12.1
func ExtractWorkerIp(regKey string) string {
	return strings.TrimPrefix(regKey, JOB_WORKER_DIR)
}
